﻿using System.IO;
using System.Linq;
using System.Threading.Tasks;
using Fee.FileAttachs;
using Fee.IO.Importers;
using Identity;
using Identity.Searcher;
using Identity.Stores;
using JwtWebApi.Data;
using JwtWebApi.Filters;
using JwtWebApi.Models.Manage;
using JwtWebApi.Models.ViewModel;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Cors;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;

namespace JwtWebApi.Controllers.Manage
{
    [Authorize]
    [Route("manage/[controller]")]
    [ApiController]
    [EnableCors]
    public class UserController : Controller
    {
        private readonly ApplicationDbContext _context;
        private readonly FileManager _fileManager;
        private readonly IDistrictStore<ApplicationDbContext> _districtStore;
        private readonly UserManager<User> _userManager;
        private readonly IVendorStore<ApplicationDbContext> _vendorStore;

        /// <summary>
        /// </summary>
        /// <param name="userManager"></param>
        public UserController(UserManager<User> userManager, ApplicationDbContext context,
            IVendorStore<ApplicationDbContext> vendorStore, FileManager fileManager, IDistrictStore<ApplicationDbContext> districtStore)
        {
            _userManager = userManager;
            _context = context;
            _vendorStore = vendorStore;
            _fileManager = fileManager;
            _districtStore = districtStore;
        }

        /// <summary>
        /// </summary>
        /// <param name="userSearch"></param>
        /// <returns></returns>
        [HttpGet("list")]
        public IActionResult Index([FromQuery] UserSearch userSearch)
        {

            var result = _userManager.Users.Include(f => f.District).Include(f => f.Vendor)
                .Where(user =>
                    (user.UserName == userSearch.UserName || user.NormalizedUserName == userSearch.UserName ||
                     string.IsNullOrEmpty(userSearch.UserName))
                    &&
                    (user.NormalizedEmail == userSearch.Email || user.NormalizedEmail == userSearch.Email ||
                     string.IsNullOrEmpty(userSearch.Email)
                    )
                    &&
                    (user.Name.Contains(userSearch.Name) || string.IsNullOrEmpty(userSearch.Name))
                    );

            return Json(new
            {
                data = result.Skip(userSearch.GetSkip()).Take(userSearch.PageSize ?? 30)
                    .Select(f => new UserViewModel(f, null))
                    .ToList(),
                total = result.Count()
            });
        }

        /// <summary>
        /// </summary>
        /// <param name="userViewModel"></param>
        /// <returns></returns>
        [HttpPost("save")]
        [ModelValidteFilter]
        public IActionResult Save([FromBody] UserViewModel userViewModel)
        {
            var updated = userViewModel.Id != null;
            var user = updated
                ? _userManager.Users.FirstOrDefault(f => f.Id == userViewModel.Id)
                : new User
                {
                    UserName = userViewModel.UserName
                };

            userViewModel.FillTo(user, _vendorStore, _districtStore);

            var saveUserResult = updated
                ? _userManager.UpdateAsync(user).Result
                : _userManager.CreateAsync(user).Result;


            var roles = _context.FindRolesByUserName(user.UserName);
            var existRolesNames = roles.Select(f => f.Name);
            var beAdded = userViewModel.Roles.Except(existRolesNames);
            var beRemoved = existRolesNames.Except(userViewModel.Roles);
            var saveSuccess = true;
            foreach (var roleName in beAdded)
            {
                var addRoleResult = _userManager.AddToRoleAsync(user, roleName).Result;
                saveSuccess = addRoleResult.Succeeded && saveSuccess;
            }

            var addRoleToUserResult = _userManager.RemoveFromRolesAsync(user, beRemoved).Result;
            saveSuccess = addRoleToUserResult.Succeeded && saveSuccess;

            return Json(new { successed = saveSuccess, message = "成功保存" });
        }

        [HttpGet("get/{id}")]
        public IActionResult Get(string id)
        {
            if (id == null)
                return NotFound();
            var user = _userManager.Users.Include(f => f.Vendor).Include(f => f.District).FirstOrDefault(f => f.Id == id);
            var roles = _context.UserRoles.Where(userRole => userRole.UserId == id)
                .Join(_context.Roles, f => f.RoleId, a => a.Id, (userRole, role) => role);
            return Json(new UserViewModel(user, roles.ToList()));
        }

        /// <summary>
        /// </summary>
        /// <param name="enabled"></param>
        /// <param name="id"></param>
        /// <returns></returns>
        [HttpPut("lockout/{id}/{enabled}")]
        public IActionResult Lock(bool enabled, string id)
        {
            var user = _userManager.Users.FirstOrDefault(f => f.Id == id);
            if (user == null)
                return NotFound();
            var setLockout = _userManager.SetLockoutEnabledAsync(user, enabled).Result;
            if (setLockout.Succeeded)
                return Json(new
                {
                    user.LockoutEnabled
                });

            return Json(new
            {
                user.LockoutEnabled,
                error = setLockout.Errors
            });
        }

        [HttpPut("reset-password")]
        [ModelValidteFilter]
        public IActionResult ResetPassword([FromBody] ResetPassword model)
        {
            var user = _context.GetByUserName(model.UserName);
            _userManager.RemovePasswordAsync(user).Wait();
            var idResult = _userManager.AddPasswordAsync(user, model.Password).Result;

            return Ok(new
            {
                successed = idResult.Succeeded,
                message = idResult.Succeeded ? "重置密码成功" : string.Join(";", idResult.Errors.Select(f => f.Description))
            });
        }


        [HttpPost("Import")]
        public async Task<IActionResult> Post([FromForm] IFormFile formFile, [FromRoute] string type)
        {
            // full path to file in temp location
            var filePath = _fileManager.GetTempPrivateFile(Path.GetExtension(formFile.FileName), User.Identity);
            using (var stream = new FileStream(filePath, FileMode.Create))
            {
                await formFile.CopyToAsync(stream);
            }

            var manager = new UserImport<ApplicationDbContext>(_context, _userManager);
            var importRowResults = manager.Import(filePath, out var isValidate, out var resultFilePath);

            var message = importRowResults ? "导入成功" : "导入失败";
            message += "。请点击结果文件，查看文件导入结果";
            _context.SaveChanges();
            return Json(new
            {
                successed = isValidate,
                resultFilePath,
                message
            });
        }
    }
}